home *** CD-ROM | disk | FTP | other *** search
- page 60,132
-
- ; SNIPPER is a resident utility which allows cutting out a portion
- ; of the screen. The selected portion may be printed, written
- ; to disk or entered in the keyboard buffer. Activate SNIPPER by
- ; pressing ALT-W, then position the cursor in the upper left corner of
- ; the window using the arrow keys. Press CR to fix the first corner,
- ; then expand the window with arrow keys. Finally, type "P" to print,
- ; "F" for disk file, "G" to retrieve or CR for a help menu. Press ESC
- ; any time to exit SNIPPER. When installing SNIPPER, use the optional
- ; parameters to expand it's internal buffer for displays (such as the
- ; EGA) containing more than the standard 25 rows and 80 columns.
-
- ; SNIPPER [rows,columns]
-
- ; ------------------------------------;
- ; BIOS_SEG IS THE ROM-BIOS DATA AREA ;
- ; ------------------------------------;
-
- BIOS_SEG SEGMENT AT 0040H
-
- ORG 004AH
- CRT_COLS DB ? ; CURRENT NUMBER OF COLUMNS
-
- ORG 0050H
- CURSOR_POSN DW 8 DUP(?) ; CURRENT CURSOR LOCATION
-
- ORG 0062H
- ACTIVE_PAGE DB ? ; ACTIVE PAGE FOR CGA AND EGA
-
- ORG 0084H
- ROWS DB ? ; LAST ROW NUMBER FOR EGA
-
- BIOS_SEG ENDS
-
- CSEG SEGMENT
-
- ASSUME CS:CSEG,DS:NOTHING
-
- ORG 0100H ; BEGINNING FOR .COM PROGRAMS
-
- START:
- JMP INITIALIZE ; INITIALIZATION CODE IS AT END
-
- ; --------------------------------;
- ; DATA AREA USED BY THIS PROGRAM ;
- ; --------------------------------;
-
- HOTKEY EQU 11H ; SCAN CODE FOR "W" KEY
-
- SHIFT_MASK EQU 00001000B ; MASK FOR ALT KEY
-
- COPYRIGHT DB "SNIPPER 1.0 (c) 1987 Ziff Communications Co."
- DB 13,10,"Hotkey is ALT-W",13,10,"$",1AH
-
- PROGRAMMER DB "Tom Kihlken"
-
- INSTALLED_MSG DB "Already Installed",13,10,"$"
-
- BAD_DOS_MSG DB "Requires DOS 2.0+",13,10,"$"
-
- OLDINT09 DD ? ; OLD KEYBOARD BREAK INTERRUPT VECTOR
-
- OLDINT13 DD ? ; OLD BIOS DISK IO INTERRUPT VECTOR
-
- OLDINT16 DD ? ; OLD KEYBOARD INTERRUPT VECTOR
-
- OLDINT21 DD ? ; OLD DOS FUNCTION INTERRUPT VECTOR
-
- ERR_STAT DB ? ; ERROR STATUS DURING FILE OUTPUT
-
- FILE_PROMPT DB "Enter Filename: "
-
- FILENAME DB "SCREEN.CUT" ; THE DEFAULT FILENAME
- DB 15 DUP (0) ; LEAVE ROOM FOR DRIVE AND PATH
-
- BUFF_NEXT DW BUFF_START ; POINTER TO NEXT KEY IN BUFFER
-
- BUFF_LAST DW BUFF_START ; POINTER TO LAST KEY IN BUFFER
-
- BUFF_START EQU OFFSET INITIALIZE
-
- BUFF_SIZE EQU 25*(80+2) ; ROOM FOR 25 ROWS OF 80 COLUMNS
-
- BUFF_END DW BUFF_START+BUFF_SIZE
-
- TOP_LEFT LABEL WORD ; FIRST CORNER OF WINDOW
-
- LEFT_SIDE DB 0 ; COLUMN NUMBER OF LEFT SIDE
-
- TOP_ROW DB 0 ; ROW NUMBER OF TOP SIDE
-
- BOT_RIGHT LABEL WORD ; SECOND CORNER OF WINDOW
-
- RIGHT_SIDE DB ? ; COLUMN NUMBER OR RIGHT SIDE
-
- BOT_ROW DB ? ; ROW NUMBER OF BOTTOM
-
- SEND_CHAR DW ? ; POINTER TO CHARACTER HANDLER
-
- SEND_KEYS DB 0 ; IF=1, USE KEYSTROKES FROM BUFFER
-
- WRIT_FILE DB 0 ; IF=1, NEED TO WRITE TO DISK
-
- BUSY_FLAGS DB 0 ; BIT MASKED AS FOLLOWS:
- ; 1 - DOS IS ACTIVE
- ; 2 - BIOS IO IS ACTIVE
- ; 4 - SNIPPER IS ACTIVE
-
- DOS_STAT DB 0 ; CURRENT DOS FUNCTION
-
- HELP_MENU DB 201,10 DUP(205),187
- DB 186," F - File ",186
- DB 186," P - Print",186
- DB 186," S - Save ",186
- DB 186," G - Get ",186
- DB 186,"Esc- Quit ",186
- DB 200,10 DUP(205),188
-
- ; ------------------------------------------------------------------;
- ; SNIPPER BUILDS THE WINDOW AND ACCEPTS COMMANDS FROM THE KEYBOARD ;
- ; ------------------------------------------------------------------;
- SNIPPER PROC NEAR
-
- ASSUME DS:CSEG, ES:BIOS_SEG
-
- XOR BX,BX ; BX IS INCREMENT FOR ROW/COLUMN
-
- GET_KB_KEY1:
- MOV DX,TOP_LEFT ; GET LOCATION OF FIRST CORNER
- ADD DH,BH ; ADD IN THE ROW INCREMENT
- ADD DL,BL ; ADD IN THE COLUMN INCREMENT
- CMP DL,0 ; AT LEFT EDGE OF SCREEN?
- JGE NOT_LEFT_EDGE
-
- MOV DL,CRT_COLS ; JUMP TO THE RIGHT EDGE
- DEC DL
-
- NOT_LEFT_EDGE:
- CMP DL,CRT_COLS ; AT RIGHT EDGE OF SCREEN YET?
- JB NOT_RIGHT_EDGE ; IF NOT, KEEP MOVING RIGHT
-
- XOR DL,DL ; IF YES, WRAP TO LEFT EDGE
-
- NOT_RIGHT_EDGE:
- CMP DH,0 ; AT TOP OF SCREEN YET?
- JGE NOT_AT_TOP
-
- MOV DH,ROWS ; JUMP DOWN TO THE BOTTOM
-
- NOT_AT_TOP:
- CMP DH,ROWS ; AT BOTTOM OF SCREEN?
- JLE NOT_AT_BOTTOM
-
- XOR DH,DH ; JUMP BACK TO THE TOP
-
- NOT_AT_BOTTOM:
- MOV TOP_LEFT,DX ; SAVE NEW CORNER LOCATION
- CALL REV_VIDEO ; CHANGE IT TO REVERSE VIDEO
- XOR AH,AH ; BIOS KEYBOARD INPUT
- INT 16H ; GET A KEYSTROKE
- PUSH AX
- CALL REV_VIDEO ; PUT ATTRIBUTE BACK TO NORMAL
- POP AX
- CMP AH,1 ; IS IT ESCAPE?
- JNE NOT_ESC
-
- RET ; JUST RETURN TO EXIT
-
- NOT_ESC:
- MOV BX,0FF00H ; INCREMENT TO SUBTRACT ONE ROW
- CMP AH,48H ; IS IT UP ARROW?
- JE GET_KB_KEY1
-
- MOV BX,0100H ; INCREMENT TO ADD ONE ROW
- CMP AH,50H ; IS IT DOWN ARROW?
- JE GET_KB_KEY1
-
- MOV BX,0001H ; INCREMENT TO ADD ONE COLUMN
- CMP AH,4DH ; IS IT RIGHT ARROW?
- JE GET_KB_KEY1
-
- MOV BX,00FFH ; INCREMENT TO SUBTRACT ONE COLUMN
- CMP AH,4BH ; IS IT LEFT ARROW?
- JE GET_KB_KEY1
-
- XOR BX,BX
- CMP AL,13 ; IS IT A CARRIAGE RETURN?
- JNE NOT_CR
-
- MOV DX,TOP_LEFT ; A CARRIAGE RETURN WAS PRESSED
- MOV BOT_RIGHT,DX ; INITIALIZE THE SECOND CORNER
- CALL REV_VIDEO ; CHANGE IT BACK TO REVERSE VIDEO
- JMP SHORT GET_KB_KEY2
-
- NOT_CR:
- CMP AH,22H ; IS IT THE "G" KEY
- JE TYPE_BUFF ; IF YES, THAN GET THE WINDOW
-
- JMP GET_KB_KEY1 ; JUST GET ANOTHER KEY
-
- TYPE_BUFF:
- MOV SEND_KEYS,1 ; SIGNAL TO SEND THE KEYS
- RET
-
- GET_KB_KEY2:
- XOR AH,AH
- INT 16H ; GET A KEYSTROKE
-
- GOT_KEY2:
- MOV DX,BOT_RIGHT
- CMP AH,48H ; IS IT UP ARROW?
- JE SUB_ROW ; SUBTRACT A ROW FROM WINDOW
-
- CMP AH,50H ; IS IT DOWN ARROW?
- JE ADD_ROW ; ADD A ROW TO THE WINDOW
-
- CMP AH,4DH ; IS IT RIGHT ARROW?
- JE ADD_COL ; ADD A COLUMN TO THE WINDOW
-
- CMP AH,4BH ; IS IT LEFT ARROW?
- JE SUB_COL ; SUBTRACT A COLUMN FROM WINDOW
-
- JMP NOT_ARROW_KEY
-
- SUB_COL:
- DEC DL ; SUBTRACT A COLUMN
- CMP DL,LEFT_SIDE ; DONT ERASE IT COMPLETELY
- JL GET_KB_KEY2
-
- MOV RIGHT_SIDE,DL ; SAVE NEW RIGHT SIDE COLUMN
- INC DL
- JMP SHORT COL_LOOP
-
- ADD_COL:
- INC DL ; ADD A COLUMN
- CMP DL,CRT_COLS ; AT RIGHT EDGE OF SCREEN?
- JAE GET_KB_KEY2 ; STOP WHEN SCREEN IS FILLED
-
- MOV RIGHT_SIDE,DL ; SAVE NEW RIGHT SIDE COLUMN
-
- COL_LOOP:
- CALL REV_VIDEO ; REVERSE THIS CHARACTER
- DEC DH ; MOVE TO NEXT ROW
- CMP DH,TOP_ROW ; AT TOP ROW YET?
- JGE COL_LOOP ; LOOP UNTIL AT TOP ROW
-
- JMP GET_KB_KEY2
-
- SUB_ROW:
- DEC DH
- CMP DH,TOP_ROW ; AT TOP OF WINDOW?
- JL GET_KB_KEY2 ; DONT ERASE IT COMPLETELY
-
- MOV BOT_ROW,DH
- INC DH
- JMP SHORT ROW_LOOP
-
- ADD_ROW:
- INC DH
- CMP DH,ROWS ; AT BOTTOM OF SCREEN?
- JG GET_KB_KEY2 ; STOP WHEN SCREEN IS FILLED
-
- MOV BOT_ROW,DH
-
- ROW_LOOP:
- CALL REV_VIDEO ; REVERSE THIS CHARACTER
- DEC DL ; MOVE TO NEXT COLUMN
- CMP DL,LEFT_SIDE ; AT LEFT EDGE YET?
- JGE ROW_LOOP ; CONTINUE UNTIL AT LEFT EDGE
-
- JMP GET_KB_KEY2
-
- NOT_ARROW_KEY:
- CMP AH,19H ; WAS IT THE "P" KEY?
- JNE NOT_P
-
- MOV SEND_CHAR,OFFSET PRINT_CHAR
- JMP READ_WINDOW
-
- NOT_P:
- MOV BUFF_NEXT,BUFF_START
- MOV BUFF_LAST,BUFF_START
- MOV SEND_CHAR,OFFSET BUFF_CHAR
- CMP AH,1FH ; WAS IT THE "S" KEY?
- JNE NOT_S
-
- MOV SEND_CHAR,OFFSET BUFF_CHAR
- JMP READ_WINDOW
-
- NOT_S:
- CMP AH,22H ; IS IT THE "G" KEY
- JNE NOT_G
-
- MOV SEND_KEYS,1
- JMP READ_WINDOW
-
- NOT_G:
- CMP AH,21H ; IS IT THE "F" KEY
- JNE NOT_F
-
- MOV WRIT_FILE,0
- CALL GET_FILENAME
- CMP WRIT_FILE,-1 ; WAS ESCAPE REQUESTED?
- JE ERASE_BOX
-
- CALL READ_WINDOW
- MOV WRIT_FILE,1
- TEST BUSY_FLAGS,00000011B ; IS INT21 OR INT13 BUSY?
- JNZ RETURN ; IF YES, WAIT TILL LATER
-
- CALL WRITE_TO_FILE ; IF NOT, DO IT NOW
-
- RETURN:
- RET
-
- NOT_F:
- CMP AH,1 ; IS IT ESCAPE?
- JE ERASE_BOX ; IF YES, ERASE BOX AND EXIT
-
- CMP AL,13 ; IS IT A CARRIAGE RETURN?
- JE DISPLAY_HELP ; IF YES, DISPLAY HELP
-
- JMP GET_KB_KEY2 ; OTHERWISE JUST GET ANOTHER KEY
-
- ERASE_BOX:
- MOV SEND_CHAR,OFFSET RETURN
- JMP READ_WINDOW
-
- DISPLAY_HELP:
- CALL EXCHANGE_HELP ; PUT UP THE HELP MENU
- XOR AH,AH
- INT 16H ; GET ANOTHER KEYSTROKE
- PUSH AX ; SAVE THE KEYSTROKE
- CALL EXCHANGE_HELP ; PULL DOWN THE HELP MENU
- POP AX ; GET BACK THE KEYSTROKE
- JMP GOT_KEY2
-
- ; *********************************************************************
- REV_VIDEO:
- CALL READ_CHAR ; READ CHARACTER AND ATTRIBUTE
- MOV BL,AH ; SAVE ATTRIBUTE IN BL
- AND BL,10001000B ; GET BLINK AND INTENSITY BITS
- AND AH,01110111B ; NOW LOOK ONLY AT COLOR BITS
- MOV CL,4 ; ROTATE FOUR COUNTS
- ROR AH,CL ; ROTATE FOREGROUND AND BACKGROUND
- OR BL,AH ; PUT BACK BLINK AND INTENSITY BITS
- CALL DISPLAY_CHAR ; WRITE CHARACTER AND ATTRIBUTE
- RET
-
- ; *********************************************************************
- READ_WINDOW:
- MOV DX,TOP_LEFT ; GET LOCATION OF FIRST CORNER
-
- READ_LOOP:
- CALL REV_VIDEO ; PUT ATTRIBUTE BACK TO NORMAL
- CALL READ_CHAR ; READ THE CHARACTER
- CALL SEND_CHAR ; CALL TO THE POINTER
- INC DL ; NEXT CHAR IN ROW
- CMP DL,RIGHT_SIDE ; AT THE RIGHT BORDER YET?
- JLE READ_LOOP ; DO ALL CHARACTERS IN THIS ROW
-
- CALL CR_LF ; SEND CR-LF AFTER EACH ROW
- INC DH ; MOVE TO NEXT ROW
- MOV DL,LEFT_SIDE ; BACK TO LEFT EDGE
- CMP DH,BOT_ROW ; AT THE BOTTOM BORDER YET?
- JLE READ_LOOP ; READ ENTIRE WINDOW
-
- RET
-
- ; *********************************************************************
- CR_LF:
- MOV AL,13
- CALL SEND_CHAR ; SEND A CARRIAGE RETURN
- MOV AL,10
- CALL SEND_CHAR ; SEND A LINE FEED
- RET
-
- ; *********************************************************************
- DISPLAY_CHAR:
- PUSH BX ; SAVE THE ATTRIBUTE
- CALL GET_CURS_ADDR ; GET ADDRESS OF BIOS CURSOR
- MOV ES:[BX],DX ; TELL BIOS WHERE THE CURSOR IS
- POP BX ; GET BACK THE ATTRIBUTE
- MOV BH,ACTIVE_PAGE ; GET ACTIVE PAGE
- PUSH CX ; SAVE THE LOOP COUNT
- MOV CX,1 ; WRITE 1 CHARACTER
- MOV AH,9 ; WRITE CHARACTER AND ATTRIBUTE
- INT 10H
- POP CX ; RECOVER LOOP COUNT
- RET ; DONE WRITING THE CHARACTER
-
- ; *********************************************************************
- READ_CHAR:
- CALL GET_CURS_ADDR ; GET ADDRESS OF BIOS CURSOR
- MOV ES:[BX],DX ; TELL BIOS WHERE THE CURSOR IS
- MOV BH,ACTIVE_PAGE ; GET ACTIVE PAGE
- MOV AH,8 ; BIOS FUNCTION TO READ CHARACTER
- INT 10H ; READ THE CHARACTER/ATTRIBUTE
- RET
-
- ; *********************************************************************
- PRINT_CHAR:
- PUSH DX
- XOR AH,AH ; USE FUNCTION 0
- XOR DX,DX ; PRINTER NUMBER 0
- INT 17H ; BIOS PRINT CHARACTER FUNCTION
- ROR AH,1 ; LOOK AT BIT ZERO
- JNC PRINT_OK ; DID A TIMEOUT OCCUR?
-
- MOV SEND_CHAR,OFFSET RETURN
-
- PRINT_OK:
- POP DX
- RET ; DONE PRINTING CHARACTER
-
- ; *********************************************************************
- BUFF_CHAR:
- MOV BX,BUFF_LAST ; GET LOCATION OF LAST CHARACTER
- MOV [BX],AL ; PUT THE CHARACTER IN BUFFER
- INC BX ; ADVANCE THE POINTER
- MOV BUFF_LAST,BX ; CHECK FOR BUFFER FULL
- CMP BX,BUFF_END ; IS THE BUFFER FULL YET?
- JNE BUFF_OK ; IF NOT, KEEP GOING
-
- MOV SEND_CHAR,OFFSET RETURN
-
- BUFF_OK:
- RET ; NOW ITS IN THE BUFFER
-
- ; *********************************************************************
- GET_CURS_ADDR:
- MOV BL,ACTIVE_PAGE ; GET THE CURRENT PAGE NUMBER
- XOR BH,BH ; CONVERT TO A WORD OFFSET
- SHL BX,1 ; TIMES TWO FOR A WORD
- ADD BX,OFFSET CURSOR_POSN ; ADD IN BASE ADDRESS
- RET
-
- ; *********************************************************************
- EXCHANGE_HELP:
- XOR DX,DX ; START AT TOP LEFT CORNER
- LEA SI,HELP_MENU
-
- EXCHANGE_LOOP:
- CMP DL,12 ; AT LAST COLUMN IN THIS ROW YET?
- JL SWAP_CHAR
-
- XOR DL,DL ; BACK TO FIRST COLUMN
- INC DH ; DO THE NEXT ROW
- CMP DH,7 ; AT LAST ROW YET?
- JL SWAP_CHAR ; QUIT WHEN LAST ROW IS DONE
-
- RET
-
- SWAP_CHAR:
- CALL READ_CHAR ; READ CHARACTER AT THIS POSITION
- XCHG AL,CS:[SI] ; SWAP WITH THE HELP TEXT
- MOV BL,AH ; ATTRIBUTE IS THE SAME
- CALL DISPLAY_CHAR ; PUT NEW CHARACTER ON SCREEN
- INC DL ; POINT TO NEXT POSITION
- INC SI
- JMP EXCHANGE_LOOP
-
- ; *********************************************************************
- GET_FILENAME:
- LEA SI,FILE_PROMPT ; POINT TO THE PROMPT FOR SOURCE
- XOR DI,DI ; USE THE PSP FOR BUFFER
- XOR DX,DX ; PUT PROMPT AT TOP LEFT CORNER
- MOV CX,40 ; USE MAX OF 40 CHARACTERS
-
- DISPLAY_PROMPT:
- PUSH CX ; SAVE LOOP COUNT
- CALL READ_CHAR ; GET CHARACTER ON THIS LINE
- MOV CS:[DI],AX ; STORE IT IN THE PSP
- INC DI ; ADD TWO FOR NEXT CHARACTER
- INC DI
- MOV AL,CS:[SI] ; GET NEXT PROMPT CHARACTER
- INC SI ; NEXT CHARACTER IN PROMPT
- MOV BL,47H ; ATTRIBUTE FOR PROMPT
- CALL DISPLAY_CHAR ; PUT UP THE PROMPT CHARACTER
- INC DL ; POINT TO NEXT COLUMN
- POP CX ; GET BACK LOOP COUNT
- LOOP DISPLAY_PROMPT ; ENTIRE PROMPT AND FILENAME
-
- FIND_LAST_LETTER:
- DEC SI ; BACKUP TO LAST LETTER
- DEC DL ; BACKUP TO LAST COLUMN
- CMP BYTE PTR [SI],0 ; IS THIS A LETTER?
- JE FIND_LAST_LETTER; BACKUP UNTIL A LETTER IS FOUND
-
- INC DL ; PUT BLINKING BOX AT LAST LETTER
-
- READ_KB:
- MOV AL,219 ; ASCII FOR BOX CHARACTER
- MOV BL,47H+80H ; MAKE IT A BLINKING BOX CHARACTER
- CALL DISPLAY_CHAR ; WRITE THE BLINKING BOX
- XOR AH,AH ; FUNCTIO 0 TO GET NEXT KEY
- INT 16H ; BIOS KEYBOARD INPUT
- CMP AL,13 ; IS IT A CARRIAGE RETURN?
- JE ERASE_PROMPT
-
- CMP AL,8 ; IS IT A BACKSPACE?
- JE BACK_SPACE
-
- CMP AH,1 ; IS IT ESCAPE?
- JE ESC_RET
-
- CMP AL,"." ; IS IT A VALID LETTER?
- JL READ_KB
-
- CMP AL,"z" ; IS IT A VALID LETTER?
- JG READ_KB
-
- CMP DL,39 ; ONLY ALLOW 40 CHARACTERS
- JGE READ_KB
-
- TTY_KEY:
- MOV BL,47H ; ATTRIBUTE FOR FILENAME
- CALL DISPLAY_CHAR ; WRITE THE LETTER
- INC DL ; MOVE TO NEXT COLUMN
- JMP READ_KB ; GET ANOTHER KEYSTROKE
-
- BACK_SPACE:
- CMP DL,16 ; AT BEGINNING OF LINE?
- JLE READ_KB ; IF YES, CAN'T BACKUP FROM HERE
-
- MOV AL,0 ; WRITE A NORMAL BLANK (ASCII 0)
- MOV BL,47H ; ATTRIBUTE FOR FILENAME
- CALL DISPLAY_CHAR ; WRITE THE LETTER
- DEC DL ; BACKUP THE CURSOR
- JMP READ_KB ; THEN GET THE NEXT KEY
-
- ESC_RET:
- MOV WRIT_FILE,-1 ; INDICATE ESCAPE IS REQUESTED
-
- ERASE_PROMPT:
- XOR AL,AL ; GET RID OF THE CURSOR
- CALL DISPLAY_CHAR ; WRITE THE LETTER
- LEA DI,FILE_PROMPT ; COPY TO FILENAME
- XOR SI,SI ; COPY FROM PSP
- XOR DX,DX ; PROMPT IS AT ROW ZERO
- MOV CX,40 ; COPY ALL 40 CHARACTERS
-
- ERASE_LOOP:
- CALL READ_CHAR ; GET CHARACTER ON THIS LINE
- MOV CS:[DI],AL ; PUT IN BACK IN MEMORY
- INC DI
- MOV AX,CS:[SI] ; GET THE ORIGINAL CHARACTER BACK
- MOV BL,AH ; PUT ATTRIBUTE INTO BL
- INC SI
- INC SI
- CALL DISPLAY_CHAR ; WRITE ORIGINAL CHARACTER
- INC DL ; MOVE TO NEXT COLUMN
- LOOP ERASE_LOOP ; ERASE THE ENTIRE PROMPT
- RET
-
- SNIPPER ENDP
-
- ; ----------------------------------------------------------------------;
- ; THIS COPIES THE BUFFER CONTENTS TO A FILE. IT SHOULD ONLY BE CALLED ;
- ; WHEN DOS IS IN A STABLE AND REENTRANT CONDITION. ;
- ; ----------------------------------------------------------------------;
-
- WRITE_TO_FILE PROC NEAR
-
- ASSUME DS:NOTHING, ES:NOTHING
-
- MOV WRIT_FILE,0 ; TURN OFF REQUEST FLAG
- PUSH AX ; MUST PRESERVE ALL REGISTERS
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DS
- PUSH ES
- PUSH CS
- POP DS
-
- ASSUME DS:CSEG ; DS POINTS TO OUR CODE SEGMENT
-
- MOV AX,3524H ; GET DOS CRITICAL ERROR VECTOR
- INT 21H ; DOS FUNCTION TO GET VECTOR
- PUSH BX ; SAVE OLD VECTOR ON STACK
- PUSH ES
-
- ; REPLACE THE DOS SEVERE ERROR INTERRUPT WITH OUR OWN ROUTINE.
-
- MOV DX,OFFSET NEWINT24
- MOV AX,2524H ; SETUP TO CHANGE INT 24h VECTOR
- INT 21H ; CHANGE DOS SEVERE ERROR VECTOR
- MOV DX,OFFSET FILENAME ; POINT TO FILENAME
-
- ; FIRST TRY TO OPEN THE FILE. IF DOS RETURNS WITH THE CARRY FLAG SET,
- ; THE FILE DIDN'T EXIST AND WE MUST CREATE IT. ONCE THE FILE IS OPENED,
- ; ADVANCE THE FILE POINTER TO THE END OF FILE TO APPEND.
-
- MOV AX,3D02H ; DOS FUNCTION TO OPEN FILE
- INT 21H ; DOS WILL RETURN WITH CARRY FLAG
- JC FILE_NOT_FOUND ; SET IF FILE DOESN'T EXIST.
-
- MOV BX,AX ; KEEP HANDLE IN BX ALSO
- XOR CX,CX ; MOVE DOS FILE POINTER TO THE
- XOR DX,DX ; END OF THE FILE. THIS LETS US
- MOV AX,4202H ; APPEND THIS TO AN EXISTING FILE
- INT 21H ; DOS FUNCTION TO MOVE POINTER
- JNC WRITE_FILE ; IF NO ERROR, CONTINUE TO WRITE
-
- DOS_ERROR:
- CMP ERR_STAT,0 ; DID A SEVERE ERROR OCCUR?
- JNE REP_VECTOR ; IF SEVERE ERROR, JUST QUIT
-
- JMP SHORT CLOSE_FILE; JUST CLOSE THE FILE
-
- FILE_NOT_FOUND:
- CMP ERR_STAT,0 ; DID A SEVERE ERROR OCCUR?
- JNE REP_VECTOR ; IF SEVERE ERROR, JUST QUIT
-
- MOV CX,0020H ; ATTRIBUTE FOR NEW FILE
- MOV AH,3CH ; CREATE FILE FOR WRITING
- INT 21H ; DOS FUNCTION TO CREATE FILE
- JC DOS_ERROR ; ON ANY ERROR, TAKE JUMP
-
- MOV BX,AX ; SAVE HANDLE IN BX
-
- WRITE_FILE:
- MOV DX,BUFF_START ; POINT TO BUFFER
- MOV CX,BUFF_LAST ; GET BUFFER POINTER
- SUB CX,DX ; NUMBER OF CHARS IN BUFFER
- MOV AH,40H ; DOS WRITE TO A DEVICE FUNCTION
- INT 21H ; WRITE TO THE FILE
-
- CLOSE_FILE:
- MOV AH,3EH ; DOS FUNCTION TO CLOSE THE FILE
- INT 21H
-
- REP_VECTOR:
- POP DS ; GET INT 24H VECTOR FROM STACK
- POP DX
- MOV AX,2524H ; RESTORE CRITICAL ERROR VECTOR
- INT 21H ; DOS FUNCTION TO CHANGE VECTOR
- POP ES ; FINALLY RESTORE ALL REGISTERS
- POP DS
- POP DX
- POP CX
- POP BX
- POP AX
- RET ; FINISHED WRITING TO DISK
-
- WRITE_TO_FILE ENDP
-
- ; ----------------------------------------------------------------------;
- ; INTERRUPT 09 ROUTINE. WATCH FOR TRIGGER KEY TO POP UP. ;
- ; ----------------------------------------------------------------------;
-
- NEWINT09 PROC FAR
-
- ASSUME DS:NOTHING, ES:NOTHING
-
- STI ; ALLOW OTHER INTERRUPTS
- PUSH AX ; MUST SAVE PROCESSOR STATE
- IN AL,60H ; GET THE SCAN CODE
- CMP AL,HOTKEY ; IS IT THE HOT KEY?
- JE TRIGGER ; IF YES, CHECK THE MASK
-
- INT09_EXIT:
- POP AX ; RESTORE THE PROCESSOR STATE
- JMP OLDINT09 ; CONTINUE WITH ROM ROUTINE
-
- TRIGGER:
- MOV AH,2 ; GET KEYBOARD STATUS
- INT 16H ; BIOS KEYBOARD SERVICE
- AND AL,0FH ; Take lower four bits
- CMP AL,SHIFT_MASK ; IS ALT KEY DOWN?
- JNZ INT09_EXIT ; IF NOT, IGNORE IT
-
- TEST BUSY_FLAGS,00000100B ; IS SNIPPER ALREADY ACTIVE?
- JNZ INT09_EXIT ; IF ACTIVE, THEN EXIT
-
- OR BUSY_FLAGS,00000100B ; ITS ACTIVE NOW
- PUSHF
- CALL OLDINT09 ; LET ROM PROCESS THE KEY
- PUSH BX ; MUST PRESERVE ALL REGISTERS
- PUSH CX
- PUSH DX
- PUSH BP
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- PUSH CS
- POP DS ; SET DS TO CSEG
- MOV AX,BIOS_SEG ; ES POINTS TO BIOS DATA AREA
- MOV ES,AX
-
- ASSUME DS:CSEG, ES:BIOS_SEG
-
- CALL GET_CURS_ADDR ; CURSOR ADDRESS FOR THIS PAGE
- PUSH ES:[BX] ; SAVE THE CURSOR LOCATION
- CALL SNIPPER ; DO THE WINDOW
- CALL GET_CURS_ADDR ; CURS0R ADDRESS FOR THIS PAGE
- POP ES:[BX] ; GET BACK CURSOR POSITION
- AND BUSY_FLAGS,11111011B ; SNIPPER IS NOT ACTIVE
- POP ES ; RESTORE ALL REGISTERS
- POP DS
- POP DI
- POP SI
- POP BP
- POP DX
- POP CX
- POP BX
- POP AX
- IRET ; NOW WERE ALL DONE
-
- NEWINT09 ENDP
-
- ; ----------------------------------------------------------------------;
- ; INTERRUPT 13 ROUTINE. SET BIOS BUST BIT ;
- ; ----------------------------------------------------------------------;
-
- NEWINT13 PROC FAR
-
- ASSUME DS:NOTHING, ES:NOTHING
-
- OR BUSY_FLAGS,00000010B ; SET BIOS BUSY BIT
- PUSHF
- CALL OLDINT13 ; DO THE BIOS FUNCTION
- PUSHF ; SAVE RESULT FLAGS
- AND BUSY_FLAGS,11111101B ; CLEAR BIOS BUSY BIT
- POPF ; GET BACK RESULT FLAGS
- STI ; MUST RETURN WITH INTERUPTS ON
- RET 2 ; RETURN BIOS RESULT FLAGS
-
- NEWINT13 ENDP
-
- ; ----------------------------------------------------------------------;
- ; INTERRUPT 16 ROUTINE. INSERT KEYSTROKES FROM BUFFER ;
- ; ----------------------------------------------------------------------;
-
- NEWINT16 PROC FAR
-
- ASSUME DS:NOTHING, ES:NOTHING
-
- PUSH BX
- CMP SEND_KEYS,1 ; SENDING KEYS FROM BUFFER?
- JE INSERT_KEY ; IF YES, THEN GET NEXT ONE
-
- CMP WRIT_FILE,1 ; ANYTHING TO WRITE TO DISK?
- JE CHECK_DOS_STAT ; IF YES, THIS IS THE TIME
-
- BIOS_KB:
- POP BX
- JMP OLDINT16 ; JUST DO NORMAL KB ROUTINE
-
- CHECK_DOS_STAT:
- CMP DOS_STAT,0AH ; DOING READ STRING?
- JE BEGIN_NOW ; IF YES, ITS SAFE TO BEGIN
-
- CMP DOS_STAT,8 ; DOING KEYBOARD INPUT?
- JNE BIOS_KB ; IF YES, ITS SAFE TO BEGIN
-
- BEGIN_NOW:
- STI ; GET INTERRUPTS BACK ON
- CALL WRITE_TO_FILE ; EMPTY THE BUFFER
- JMP BIOS_KB ; CONTINUE WITH BIOS ROUTINE
-
- INSERT_KEY:
- STI ; INTERRUPTS BACK ON
- MOV BX,BUFF_NEXT ; GET ADDRESS OF NEXT BYTE
- CMP BX,BUFF_LAST ; AT END OF BUFFER YET?
- JL GET_A_KEY ; IF NOT, GET THE NEXT ONE
-
- MOV SEND_KEYS,0 ; WHEN DONE, TURN OFF SEND SWITCH
-
- GET_A_KEY:
- MOV AL,CS:[BX] ; GET THE NEXT KEY CODE
- CMP AL,10 ; IS IT A LINE FEED?
- JNE NOT_LF ; DONT RETURN THE LINE FEEDS
-
- INC BUFF_NEXT ; SKIP TO NEXT KEY
- JMP INSERT_KEY
-
- NOT_LF:
- CMP AH,1 ; REQUEST FOR STATUS ONLY?
- JE RETURN_STATUS ; IF YES, RETURN STATUS ONLY
-
- CMP AH,0 ; REQUEST TO GET THE NEXT KEY
- JNE BIOS_KB ; IF NOT, IGNORE THIS FUNCTION
-
- INC BX ; REMOVE THIS KEY FROM OUR BUFFER
- MOV BUFF_NEXT,BX ; SAVE THE POINTER TO NEXT KEY
-
- RETURN_STATUS:
- OR BL,1 ; CLEAR ZERO FLAG TO INDICATE A
- POP BX ; KEY IS AVAILIABLE
- RET 2 ; RETURN WITH THESE FLAGS
-
- NEWINT16 ENDP
-
- ; ----------------------------------------------------------------------;
- ; INTERRUPT 21 ROUTINE. THIS ROUTINE IS USED TO MONITOR DOS FUNCTION ;
- ; CALLS. IF THE BUFFER NEEDS TO BE FLUSHED, IT WIL BE DONE HERE. ;
- ; ----------------------------------------------------------------------;
-
- NEWINT21 PROC FAR
-
- ASSUME DS:NOTHING, ES:NOTHING
-
- STI
- OR AH,AH ; DOING FUNCTION ZERO?
- JNE NOT_ZERO
-
- MOV AH,4CH ; IF YES, CHANGE IT TO A 4CH
-
- NOT_ZERO:
- OR BUSY_FLAGS,00000001B ; SET DOS BUSY BIT
- MOV DOS_STAT,AH
- PUSHF ; SIMULATE AN INTERRUPT
- CALL OLDINT21 ; DO THE DOS FUNCTION
- PUSHF ; SAVE THE RESULT FLAGS
- AND BUSY_FLAGS,11111110B ; CLEAR DOS BUSY BIT
- CMP WRIT_FILE,1 ; ANYTHING TO WRITE TO DISK?
- JNE NO_WRITE ; IF NOT JUST RETURN
-
- CALL WRITE_TO_FILE ; SAFE TO ACCESS DISK NOW
-
- NO_WRITE:
- POPF ; RECOVER DOS RESULT FLAGS
- RET 2 ; RETURN WITH DOS RESULT FLAGS
-
- NEWINT21 ENDP
-
- ; ----------------------------------------------------------------------;
- ; NEW INTERRUPT 24H (CRITICAL DOS ERROR). THIS INTERRUPT IS ONLY IN ;
- ; EFFECT ONLY DURING A WRITE SCREEN. IT IS REQUIRED TO SUPPRESS THE ;
- ; 'ABORT, RETRY, IGNORE' MESSAGE. ALL FATAL DISK ERRORS ARE IGNORED. ;
- ; ----------------------------------------------------------------------;
-
- NEWINT24 PROC FAR
-
- ASSUME CS:CSEG, DS:NOTHING, ES:NOTHING
-
- STI ; TURN INTERRUPTS BACK ON
- INC ERR_STAT ; SET THE ERROR FLAG
- XOR AL,AL ; TELLS DOS TO IGNORE THE ERROR
- IRET ; THATS ALL WE DO HERE
-
- NEWINT24 ENDP
-
- ; ----------------------------------------------------------------------;
- ; HERE IS THE CODE USED TO INITIALIZE SNIPPER. ;
- ; ----------------------------------------------------------------------;
-
- ASSUME CS:CSEG, DS:CSEG, ES:CSEG
-
- INITIALIZE:
- LEA DX,COPYRIGHT
- MOV AH,9 ; DOS DISPLAY STRING SERVICE
- INT 21H ; DISPLAY TITLE MESSAGE
-
- ; SEARCH FOR AN PREVIOUSLY INSTALLED COPY OF SNIPPER
-
- NOT BYTE PTR START ; MODIFY TO AVOID FASLE MATCH
- XOR BX,BX ; START SEARCH AT SEGMENT ZERO
- MOV AX,CS ; COMPARE TO THIS CODE SEGMENT
-
- NEXT_SEGMENT:
- INC BX ; LOOK AT NEXT SEGMENT
- CMP AX,BX ; UNTIL REACHING THIS CODE SEG
- MOV ES,BX
- JE NOT_INSTALLED
-
- LEA SI,START ; SETUP TO COMPARE STRINGS
- MOV DI,SI
- MOV CX,16 ; 16 BYTES MUST MATCH
- REP CMPSB ; COMPARE DS:SI TO ES:DI
- OR CX,CX ; DID THE STRINGS MATCH?
- JNZ NEXT_SEGMENT ; IF NO MATCH, TRY NEXT SEGMENT
-
- LEA DX,INSTALLED_MSG
- JMP SHORT ERR_EXIT
-
- NOT_INSTALLED:
- MOV AH,30H
- INT 21H ; GET DOS VERSION NUMBER
- CMP AL,2 ; IS IT HIGHER THAN 2.0?
- JAE VER_OK ; IF YES, PROCEED
-
- LEA DX,BAD_DOS_MSG
-
- ERR_EXIT:
- MOV AH,9 ; DOS DISPLAY STRING SERVICE
- INT 21H ; DISPLAY ERRER MESSAGE
- RET ; RETURN TO DOS
-
- VER_OK:
- INC SI ; POINT TO FIRST PARAMETER
- MOV SI,81H ; POINT TO PARAMETER AREA
- CALL GET_PARAM ; GET FIRST PARAMETER (ROWS)
- PUSH AX ; SAVE THE ROW COUNT
- CALL GET_PARAM ; GET SECOND PARAMETER (COLUMNS)
- ADD AX,2 ; ADD SPACE FOR CR AND LF
- POP BX ; GET BACK FIRST PARAMETER
- MUL BX ; PRODUCT OF ROWS AND COLUMNS
- OR AX,AX ; WAS ANYTHING ENTERED?
- JZ NO_PARAMS ; IF NOT, USE DEFAULT VALUE
-
- CMP AX,10000 ; MAXIMUM BUFFER IS 10000 BYTES
- JLE SIZE_IS_OK
-
- MOV AX,10000
-
- SIZE_IS_OK:
- ADD AX,BUFF_START
- MOV BUFF_END,AX ; SET THE NEW BUFFER SIZE
-
- NO_PARAMS:
- MOV AX,BIOS_SEG ; LOOK AT BIOS DATA AREA
- MOV ES,AX
-
- ASSUME ES:BIOS_SEG
-
- CMP ROWS,0 ; IS NUMBER OF ROWS ENTERED HERE
- JNE MUST_BE_EGA ; IF YES, AN EGA MAY BE PRESENT
-
- MOV ROWS,24 ; IF NOT EGA, MUST BE 24 ROWS
-
- MUST_BE_EGA:
-
- ASSUME ES:NOTHING
-
- MOV AX,3509H ; GET KEYBOARD BREAK VECTOR
- INT 21H
- MOV WORD PTR [OLDINT09],BX ; SAVE SEGMENT
- MOV WORD PTR [OLDINT09+2],ES; SAVE OFFSET
- MOV DX, OFFSET NEWINT09
- MOV AX, 2509H
- INT 21H ; DOS FUNCTION TO CHANGE VECTOR
- MOV AX,3513H ; GET BIOS DISK INTERRUPT VECTOR
- INT 21H
- MOV WORD PTR [OLDINT13],BX ; SAVE SEGMENT
- MOV WORD PTR [OLDINT13+2],ES; SAVE OFFSET
- MOV DX, OFFSET NEWINT13
- MOV AX, 2513H
- INT 21H ; DOS FUNCTION TO CHANGE VECTOR
- MOV AX,3516H ; GET KEYBOARD INPUT VECTOR
- INT 21H
- MOV WORD PTR [OLDINT16],BX ; SAVE SEGMENT
- MOV WORD PTR [OLDINT16+2],ES; SAVE OFFSET
- MOV DX, OFFSET NEWINT16
- MOV AX, 2516H
- INT 21H ; DOS FUNCTION TO CHANGE VECTOR
- MOV AX,3521H ; GET DOS FUNCTION VECTOR
- INT 21H
- MOV WORD PTR [OLDINT21],BX
- MOV WORD PTR [OLDINT21+2],ES
- MOV DX, OFFSET NEWINT21
- MOV AX, 2521H
- INT 21H ; DOS FUNCTION TO CHANGE VECTOR
-
- ; ----------------------------------------------------------------------;
- ; DEALLOCATE OUR COPY OF THE ENVIORNMENT. ;
- ; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR BUFFER RESIDENT. ;
- ; ----------------------------------------------------------------------;
-
- MOV AX,DS:[002CH] ; GET SEGMENT OF ENVIORNMENT
- MOV ES,AX ; PUT IT INTO ES
- MOV AH,49H ; RELEASE ALLOCATED MEMORY
- INT 21H
- MOV DX,BUFF_END ; LEAVE THIS MUCH RESIDENT
- INT 27H ; TEMINATE AND STAY RESIDENT
-
- ; ------------------------------------------------------;
- ; GET_PARAM RETRIEVES AN INTEGER FROM THE COMMAND LINE. ;
- ; ------------------------------------------------------;
-
- GET_PARAM:
- XOR AX,AX ; CLEAR AX FOR TOTAL
-
- GET_DIGIT:
- MOV BL,[SI] ; GET CHARACTER INTO BL
- CMP BL,0DH ; IS IT THE LAST ONE?
- JE DONE
-
- INC SI ; POINT TO NEXT CHARACTER
- CMP BL,"," ; IS IT THE DELIMITER?
- JE DONE
-
- SUB BL,30H ; CONVERT ASCII TO INTEGER
- JC GET_DIGIT ; IS IT A VALID DIGIT
-
- CMP BL,9
- JA GET_DIGIT ; IF NOT VALID, JUST SKIP IT
-
- MOV BH,10 ; TIMES 10 FOR NEXT DIGIT
- MUL BH ; MULTIPLY SUM AND ADD THIS DIGIT
- ADD AL,BL ; ADD DIGIT TO SUM
- JMP GET_DIGIT ; READ ALL CHARACTERS ON LINE
-
- DONE:
- RET
-
- CSEG ENDS
-
- END START
-